-------------------------------------------------------------------------------
---! 战斗帧同步相关处理
-------------------------------------------------------------------------------
local M = {}
COMBAT_D:register_entry("action", M)

---! 启动帧同步计时器
function M:start_sync_timer(combat_ob)
    if combat_ob:query_temp("sync_timer_id") then
        ---! 同步帧定时器已存在，无需重复启动
        return
    end

    ---! 假定前端播放帧速率：60帧/秒
    local timer_id =
        TIMER_D:start_timer(
        0.1,
        function()
            local frame = combat_ob:query_temp("frame") or 0
            combat_ob:set_temp("frame", frame + 6)

            ---! 通过在线更新的手法，可能需要重载sync_frame方法
            -- 因此需要重新获取frame模块，再对sync_frame方法进行调用
            local module = COMBAT_D:query_entry("action")
            if module then
                module:sync_frame(combat_ob)
            end
        end
    )
    combat_ob:set_temp("sync_timer_id", timer_id)
end

---! 同步帧
function M:sync_frame(combat_ob)
    ---! 获取当前帧
    local frame_id = combat_ob:query_temp("frame") or 0

    local input = {}
    local sync_frame = combat_ob:query_temp("sync_frame")
    if sync_frame then
        ---! 优先清理缓存数据
        combat_ob:delete_temp("sync_frame")

        ---! 遍历获取所有帧数据
        for player_id, frame_data in pairs(sync_frame) do
            table.insert(
                input,
                {
                    player_id = player_id,
                    frame_data = frame_data
                }
            )
        end
    end

    local result = {}
    result.frame_id = frame_id
    result.input = input
    combat_ob:brocast_packet("tanker.S2CPlayInput", result)
end

---! 输入帧
function M:input_frame(combat_ob, user_ob, frame_data)
    local sync_frame = combat_ob:query_temp("sync_frame")
    if not sync_frame then
        sync_frame = combat_ob:set_temp("sync_frame", {})
    end

    local user_id = user_ob:get_id()
    local user_frame_data = sync_frame[user_id]
    if not user_frame_data then
        sync_frame[user_id] = table.copy(frame_data)
    else
        table.insertvalues(user_frame_data, frame_data)
    end
end

---! 被命中
function M:hitted_frame(combat_ob, user_ob, hit_user_id)
    local tank = user_ob:query_temp("tank")
    if not tank or tank:is_dead() then
        ---! 当前坦克已死亡
        return
    end

    local hit_user = combat_ob:get_player_ob(hit_user_id)
    if not hit_user then
        ---! 目标玩家不存在
        return
    end

    local hit_tank = hit_user:query_temp("tank")
    if not hit_tank or hit_tank:is_dead() then
        ---! 目标坦克已死亡
        return
    end

    ---! 获取坦克攻击力，计算伤害值（若有公式则套入公式计算）
    local damage = tank:get_attack()

    ---! 扣除目标坦克血量
    local hp = hit_tank:cost_hp(damage)

    ---! 广播消息
    local result = {}
    result.shoot_uid = user_ob:get_id()
    result.hited_uid = hit_user_id
    result.hurt = damage
    result.hp = hp
    result.mode = 0
    combat_ob:brocast_packet("tanker.S2CHit", result)

    ---! 若目标坦克已死亡
    if hit_tank:is_dead() then
        ---! 记录目坦克死亡时间
        COMBAT_D:set_dead_time(combat_ob, hit_user, hit_tank)

        ---! 累加当前坦克击毁坦克数量
        tank:add_tank_num(1)

        ---! 累加当前玩家击毁坦克数量
        user_ob:add_tank_num(1)

        ---! 已死亡数量
        combat_ob:add_dead_num(1)

        ---!发送结算界面给目标
        COMBAT_D:quit_combat(hit_user, 30)
    end

    ---! 检查战斗是否结束
    if combat_ob:is_finished() then
        COMBAT_D:finish_combat(combat_ob)
    end
end

---! 撞车
function M:crash_frame(combat_ob, user_ob, hit_mode)
    local tank = user_ob:query_temp("tank")
    if not tank or tank:is_dead() then
        ---! 当前坦克已死亡
        return
    end

    ---! 受损值 = 自身剩余血量
    local damage = tank:get_hp()

    ---! 扣除目标坦克血量
    local hp = tank:cost_hp(damage)

    ---! 广播消息
    local result = {}
    result.shoot_uid = 0
    result.hited_uid = user_ob:get_id()
    result.hurt = damage
    result.hp = hp
    result.mode = hit_mode
    combat_ob:brocast_packet("tanker.S2CHit", result)

    ---! 若目标坦克已死亡
    if tank:is_dead() then
        ---! 记录目坦克死亡时间
        COMBAT_D:set_dead_time(combat_ob, user_ob, tank)

        ---! 已死亡数量
        combat_ob:add_dead_num(1)

        ---!发送结算界面给目标
        COMBAT_D:quit_combat(user_ob, 30)
    end

    ---! 检查战斗是否结束
    if combat_ob:is_finished() then
        COMBAT_D:finish_combat(combat_ob)
    end
end
